package reading.common;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import reading.common.enums.IBaseEnum;
import reading.common.exception.HlBadRequestException;
import reading.common.exception.HlIoException;
import reading.common.exception.HlValidateException;
import reading.util.utils.StringUtil;
import reading.util.utils.TimeUtils;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author Gang.Zou on 16-11-3.
 */
public class ExcelUtil {
    private static final Object[] EMPTY = new Object[0];
    private static final String XLS = "XLS";
    private static final String XLS_X = "xlsx";
    private static final DateTimeFormatter YYYYMMDD = DateTimeFormatter.ofPattern("yyyy/MM/dd");
    private static CellStyle style;
    private static Workbook bookStatic;
    private static OutputStream outputStatic;
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
    private static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static Pattern PATTERN = Pattern.compile("\\{.+\\}");

    public static SimpleDateFormat getInstance() {
        synchronized (simpleDateFormat) {
            if (simpleDateFormat == null) {
                simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH/mm/ss");
            }
            return simpleDateFormat;
        }
    }

    public static String getRow(Row row, int cell) {
        return getString(row.getCell(cell));
    }

    public static String validateFile(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            throw new HlValidateException(400001, Arrays.asList("请选择文件!"));
        }
        int index = fileName.lastIndexOf(".");
        if (index == -1) {
            throw new HlValidateException(400002, Arrays.asList("文件格式错误,请选择excel文件!"));
        }
        String fileType = fileName.substring(index + 1, fileName.length()).toLowerCase();
        if (!XLS.equals(fileType) && !XLS_X.equals(fileType)) {
            throw new HlValidateException(400002, Arrays.asList("文件格式错误,请选择excel文件!"));
        }
        return fileType;
    }

    public static <T extends Workbook> T parseFromStream(InputStream inputStream, Class<T> c) {
        try (T t = c.getConstructor(InputStream.class).newInstance(inputStream)) {
            return t;
        } catch (Exception e) {
            throw new HlIoException(400003, Arrays.asList("解析excel文件时出现错误!"));
        }
    }

    public static void setStyle(Sheet sheet, Row row) {
        if (row != null && row.getPhysicalNumberOfCells() > 1) {
            /**
             * 列个数大于5
             * 防止取到无关列
             * 比如有时候第一行是汇总信息，只有1列，但是实际列数不止1列
             */
            for (int col = 0; col < row.getPhysicalNumberOfCells(); col++) {
                sheet.autoSizeColumn(col);
            }
        }
    }

    public static void setStyle(Sheet sheet, int cols) {
        for (int col = 0; col < cols; col++) {
            sheet.autoSizeColumn(col);
        }
    }

    public static void setStyleSingle(Sheet sheet, int col) {
        sheet.autoSizeColumn(col);
    }

    public static Workbook parseFromStream(InputStream inputStream, String fileType) {
        Workbook workbook = null;
        try {
            if (XLS.equals(fileType)) {
                workbook = new HSSFWorkbook(inputStream);
            } else {
                workbook = new XSSFWorkbook(inputStream);
            }
        } catch (IOException e) {
            throw new HlIoException(400003, Arrays.asList("解析excel文件时出现错误!"));
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return workbook;
    }

    public static <T> List<String> validateBean(List<T> list) {
        List<String> messageList = new ArrayList<>();
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        for (int i = 0; i < list.size(); i++) {
            Set<ConstraintViolation<T>> set = validator.validate(list.get(i));
            if (!CollectionUtils.isEmpty(set)) {
                for (ConstraintViolation<T> temp : set) {
                    String message = "第" + (i + 1) + "行:" + temp.getMessage();
                    messageList.add(message);
                }
            }
            if (messageList.size() >= CsConstants.EXCEL_IMPORT_MAX_ERRORS) {
                break;
            }
        }
        return messageList;
    }

    public static <T> void validate(List<T> list) throws InvocationTargetException, IllegalAccessException {
        Method method = getSetMethod(list.get(0).getClass(), "errorReason");
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        for (T t : list) {
            Set<ConstraintViolation<T>> set = validator.validate(t);
            if (!CollectionUtils.isEmpty(set)) {
                StringBuilder sb = new StringBuilder();
                for (ConstraintViolation<T> temp : set) {
                    sb.append(temp.getMessage());
                    sb.append(";");
                }
                method.invoke(t, sb.toString());
            }
        }
    }

    private static Method getSetMethod(Class c, String fieldName) {
        try {
            return new PropertyDescriptor(fieldName, c).getWriteMethod();
        } catch (IntrospectionException e) {
            throw new HlValidateException(400005, "没有名为" + fieldName + "的字段");
        }
    }

    public static String getString(Cell cell) {
        if (cell == null) {
            return null;
        }
        cell.setCellType(CellType.STRING);
        String value = cell.getStringCellValue().trim();
        if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
            return null;
        } else {
            return value;
        }
    }

    public static String getString(Row row, int cell) {
        return getString(row.getCell(cell));
    }

    public static String getString(Row row, int cell, List<String> messageList, String msg) {
        String fdxm = ExcelUtil.getString(row.getCell(cell));
        if (StringUtil.isEmpty(fdxm)) {
            messageList.add(msg);
        }
        return fdxm;
    }

    public static <E> E getString(Row row, int cell, IBaseEnum iBaseEnum) {
        return (E) iBaseEnum.stringOf(getString(row.getCell(cell)));
    }

    public static Date getDate(Row row, int cell, List<String> messageList) {
        try {
            return (row.getCell(cell).getDateCellValue());
        } catch (Exception e) {
            StringBuilder str = new StringBuilder("第").append(cell).append("行第13列:处罚决定日期应为日期格式，如：2017/01/01");
            messageList.add(str.toString());
        }
        return null;
    }


    public static int getDropdown(Cell cell) throws Exception {
        cell.setCellType(CellType.STRING);
        String str = cell.getStringCellValue();
        return Integer.parseInt(str.substring(0, str.indexOf("-")));
    }

    public static String connect(List<String> list) {
        StringBuilder sb = new StringBuilder();
        for (String str : list) {
            sb.append(str);
            sb.append(";");
        }
        return sb.toString();
    }

    public static Cell setCellValue(Cell cell, LocalDate value, CellStyle style) {
        return setCellValue(cell, TimeUtils.toDate(value), style);
    }

    public static Cell setCellValue(Cell cell, Date value, CellStyle style) {
        cell.setCellValue(value);
        cell.setCellStyle(style);
        return cell;
    }

    public static void fillString(Cell cell, String value) {
        cell.setCellType(CellType.STRING);
        if (value != null) {
            cell.setCellValue(value);
        }
    }

    public static void newInstance(String pattern) {
        simpleDateFormat = new SimpleDateFormat(pattern);
    }

    public static synchronized SimpleDateFormat getInstance(String patern) {
        return DateFormatterHolder.getSimple(patern);
    }

    public static void fillLocalDate(Cell cell, LocalDate localDate) {
        if (localDate != null) {
            cell.setCellValue(YYYYMMDD.format(localDate));
        }
    }

    public static void fillDate(Cell cell, Date date) {
        if (date != null) {
            cell.setCellValue(getInstance("yyyy/MM/dd").format(date));
        }
    }

    /**
     * 最基础的创建Row标题方法
     *
     * @param row
     * @param cell
     * @param value
     */
    public static void createTitleRow(Row row, int cell, String value) {
        row.createCell(cell).setCellValue(value);
    }

    /**
     * 最基础的创建Row方法
     *
     * @param row
     * @param cell
     * @param value
     */
    public static void createRow(Row row, int cell, String value) {
        row.createCell(cell).setCellValue(CommonUtil.isNullAndNullStr(value) ? "" : value);
    }

    public static void createRow(Row row, int cell, Object value) {
        createRow(row, cell, value == null ? "" : value.toString());
    }

    public static void createRow(Row row, int cell, LocalDateTime time) {
        if (time == null) {
            createRow(row, cell);
        } else {

            createRow(row, cell, dateTime.format(time));
        }
    }

    public static void createRow(Row row, int cell, String date, String source, String target) {
        createRow(row, cell, CommonUtil.stringDatePattern(date, "yyyyMMdd", "yyyy年MM月dd日"));
    }

    public static void createRow(Row row, int cell, Long value) {
        createTitleRow(row, cell, value == null ? "" : value.toString());
    }

    public static void createRow(Row row, int cell, LocalDate value, String pattern) {
        if (value == null) {
            createRow(row, cell);
        } else {
            DateTimeFormatter date = DateTimeFormatter.ofPattern(pattern);
            createRow(row, cell, date.format(value));
        }
    }

    public static void createRow(Row row, int cell, LocalDate value) {
        createRow(row, cell, value, "yyyy/MM/dd");
    }

    public static void createRow(Row row, int cell, Double value) {
        createTitleRow(row, cell, value == null ? "" : value.toString());
    }

    public static void createRow(Row row, int cell, Integer integer) {
        createTitleRow(row, cell, integer == null ? "" : integer.toString());
    }

    public static void createRow(Row row, int cell, BigDecimal bigDecimal) {
        createTitleRow(row, cell, bigDecimal == null ? "" : bigDecimal.toString());
    }

    public static void createRow(Row row, int cell, Date date, String pattern) {
        if (date != null) {
            createRow(row, cell, getInstance(pattern).format(date));
        } else {
            createRow(row, cell);
        }
    }

    public static void createRow(Row row, int cell, Date date, SimpleDateFormat s) {
        if (date == null) {
            createRow(row, cell);
        } else {
            createRow(row, cell, s.format(date));
        }
    }

    public static void createBoldFont(Workbook workbook) {
        style = workbook.createCellStyle();
        Font font = workbook.createFont();
        //粗体显示
        font.setBold(true);
        style.setFont(font);
    }

    public static void setBoldRow(Row row) {
        if (style != null) {
            row.setRowStyle(style);
        }
    }

    public static void createRow(Row row, int cell) {
        createTitleRow(row, cell, "");
    }

    public static void createRow(Row row, int cell, Date date) {

        createRow(row, cell, date, "yyyy/MM/dd");
    }

    public static void createRow(Row row, int cell, IBaseEnum iBaseEnum) {
        if (iBaseEnum != null) {
            createRow(row, cell, iBaseEnum.getName());
        } else {
            createRow(row, cell);
        }
    }

    public static void fileDateTime(Cell cell, Date date) {
        if (date != null) {
            cell.setCellValue(getInstance("yyyy-MM-dd HH:mm:ss").format(date));
        } else {
            cell.setCellValue("");
        }
    }

    /**
     * 导出Excel
     *
     * @param workbook
     * @param response
     * @param name
     * @throws IOException
     */
    public static void writeWorkBook(Workbook workbook, HttpServletResponse response, String name) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        String fileName = new String(name.getBytes("utf-8"), "iso-8859-1");
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName + CommonUtil.parseDate(new Date(), "yyyyMMddHHmmss") + ".xlsx");
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        workbook.close();
        outputStream.close();
    }

    public static void writeWorkBook(Workbook workbook, HttpServletResponse response, String name, String suffix) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        String fileName = new String(name.getBytes("utf-8"), "iso-8859-1");
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName + CommonUtil.parseDate(new Date(), "yyyyMMddHHmmss") + "." + suffix);
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        workbook.close();
        outputStream.close();
    }

    public static <T> void doExportForXls(HttpServletResponse response, String fileName, List<T> exportData, Class<?> entityClass) {
        doExportExcel(response, new HSSFWorkbook(), fileName, "XLS", exportData, entityClass, null);
    }

    public static <T> String doReadForXls(String rootPath, String fileName, List<T> readData, Class<?> entityClazz) {
        return doWriteExcelToFile(rootPath, new HSSFWorkbook(), fileName, "XLS", readData, entityClazz, null);
    }

    public static <T> Map<String, Object> doReadAddSheetForXls(Workbook workbook, String rootPath, String fileName, String sheetName, List<T> readData, Class<?> entityClazz) {
        return doWriteExcelToFileSheetAdd(rootPath, workbook, fileName, "XLS", sheetName, readData, entityClazz, null);
    }

    private static <T> void doExportExcel(HttpServletResponse response, Workbook workbook, String fileName,
                                          String suffix, List<T> exportData, Class<?> entityClass, List<String> filterName) {
        OutputStream output = null;
        try {
            StringBuilder builder = new StringBuilder();
            if (StringUtil.isNotBlank(fileName)) {
                builder.append(new String(fileName.getBytes("utf-8"), "iso8859-1"));
            } else {
                builder.append(System.nanoTime());
            }
            builder.append('.').append(suffix);

            output = response.getOutputStream();
            response.reset();
            response.setContentType("bin");

            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment; filename=" + builder.toString());

            createWorkbook(workbook, exportData, entityClass, filterName);
            workbook.write(output);
            output.flush();
        } catch (Exception e) {
            throw new HlBadRequestException(4000001, "失败创建excel");
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    private static <T> String doWriteExcelToFile(String rootPath, Workbook workbook, String fileName,
                                                 String suffix, List<T> exportData, Class<?> entityClass, List<String> filterName) {
        String filePath;
        OutputStream output = null;
        try {
            StringBuilder builder = new StringBuilder();
            if (StringUtil.isNotBlank(fileName)) {
                builder.append(new String(fileName.getBytes("utf-8"), "iso8859-1"));
            } else {
                builder.append(System.nanoTime());
            }
            builder.append('.').append(suffix);
            filePath = rootPath + File.separator + System.currentTimeMillis() + "." + suffix;
            File file = new File(filePath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
            output = new FileOutputStream(file);
            //写文件
            createWorkbook(workbook, exportData, entityClass, filterName);
            workbook.write(output);
            output.flush();
        } catch (Exception e) {
            throw new HlBadRequestException(4000001, "失败创建excel");
        } finally {
            IOUtils.closeQuietly(output);
        }
        return filePath;
    }

    private static <T> Map<String, Object> doWriteExcelToFileSheetAdd(String rootPath, Workbook workbook, String fileName,
                                                                      String suffix, String sheetName, List<T> exportData, Class<?> entityClass, List<String> filterName) {
        String filePath;
        OutputStream output = null;
        Map<String, Object> map = new HashMap<>(2);
        try {
            StringBuilder builder = new StringBuilder();
            if (StringUtil.isNotBlank(fileName)) {
                builder.append(new String(fileName.getBytes("utf-8"), "iso8859-1"));
            } else {
                builder.append(System.nanoTime());
            }
            builder.append('.').append(suffix);
            filePath = rootPath + File.separator + System.currentTimeMillis() + "." + suffix;
            File file = new File(filePath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
            output = new FileOutputStream(file);
            map.put("output", output);
            map.put("filepath", filePath);
            //写文件
            createWorkbookSheet(workbook, sheetName, exportData, entityClass, filterName);
        } catch (Exception e) {
            throw new HlBadRequestException(4000001, "失败创建excel");
        }
        return map;
    }


    public static void startWrite(Workbook workbook, OutputStream output) {
        try {
            workbook.write(output);
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * 导出 excel
     *
     * @param response
     * @param fileName
     * @param exports
     * @param entityClass
     * @param filterName
     * @param <T>
     * @throws IOException
     */
    public static <T> void exportXlsWorkbook(HttpServletResponse response, String fileName, List<T> exports, Class<?> entityClass, List<String> filterName) throws IOException {
        Workbook workbook = new HSSFWorkbook();
        createWorkbook(workbook, exports, entityClass, filterName);
        writeWorkBook(workbook, response, fileName, "XLS");
    }

    public static <T> void createWorkbook(Workbook book, List<T> exports, Class<?> entityClass, List<String> filterName) {
        Sheet sheet = book.createSheet();
        List<Entry> entries = new ArrayList<>();
        getEntryByEntityClass(entityClass, entries, filterName);
        // 排序
        entries.sort(Comparator.comparingInt(o -> o.order));
        createSheetTitle(sheet, entries);
        if (exports == null || exports.isEmpty()) {
            return;
        }
        createSheetBody(sheet, entityClass, entries, exports);
    }

    public static <T> void createWorkbookSheet(Workbook book, String sheetName, List<T> exports, Class<?> entityClass, List<String> filterName) {
        Sheet sheet = book.createSheet(sheetName);
        List<Entry> entrys = new ArrayList<>();
        getEntryByEntityClass(entityClass, entrys, filterName);
        // 排序
        entrys.sort(Comparator.comparingInt(o -> o.order));
        createSheetTitle(sheet, entrys);
        if (exports == null || exports.isEmpty()) {
            return;
        }
        createSheetBody(sheet, entityClass, entrys, exports);
    }

    private static <T> void getEntryByEntityClass(Class<?> entityClass, List<Entry> entrys, List<String> filterName) {
        List<Field> fields = new ArrayList<>();
        iteratorClass(entityClass, fields, filterName);
        PropertyDescriptor property;
        for (Field field : fields) {
            Export e = field.getAnnotation(Export.class);
            ExportList list = field.getAnnotation(ExportList.class);
            boolean isContinue = e == null || (filterName != null && filterName.contains(field.getName()));
            if (isContinue) {
                continue;
            }
            property = BeanUtils.getPropertyDescriptor(entityClass, field.getName());
            entrys.add(new Entry(property, e.name(), e.pattern(), e.json(), e.order()));
        }
    }

    private static void iteratorClass(Class<?> entityClass, List<Field> fields, List<String> filterField) {
        Field[] fs = entityClass.getDeclaredFields();
        for (Field f : fs) {
            if (filterField != null && filterField.contains(f.getName())) {
                continue;
            }
            fields.add(f);
        }
        Class<?> superClass = entityClass.getSuperclass();
        if (superClass != null) {
            iteratorClass(superClass, fields, filterField);
        }
    }

    private static <T> void createSheetTitle(Sheet sheet, List<Entry> entrys) {
        for (int i = 0, size = entrys.size(); i < size; i++) {
            Entry entry = entrys.get(i);
            Cell cell = getCell(sheet, 0, i);
            setCellValue(cell, entry.name, entry.pattern);
        }
    }

    private static <T> void createSheetBody(Sheet sheet, Class<?> entityClass, List<Entry> entrys, List<T> exports) {
        for (int i = 0, isize = exports.size(); i < isize; i++) {
            T export = exports.get(i);
            for (int j = 0, jsize = entrys.size(); j < jsize; j++) {
                Cell cell = getCell(sheet, (i + 1), j);
                setValueToCell(cell, export, entrys.get(j));
            }
        }
        setStyle(sheet, entrys.size());
    }

    private static <T> void setValueToCell(Cell cell, T entity, Entry entry) {
        try {
            Method method = entry.property.getReadMethod();
            Object value = method.invoke(entity, EMPTY);
            Map<Integer, String> jsonMap = entry.json;
            if (jsonMap != null && !jsonMap.isEmpty()) {
                String name = jsonMap.get(Integer.valueOf(value + ""));
                value = (StringUtil.isNotBlank(name)) ? name : "未知";
            }
            setCellValue(cell, value, entry.pattern);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取POI的行对象
     *
     * @param sheet 表对象
     * @param row   行号，从0开始
     * @return
     */
    private static Row getRow(Sheet sheet, int row) {
        row = (row < 0) ? 0 : row;
        Row r = sheet.getRow(row);
        return (r == null) ? sheet.createRow(row) : r;
    }

    /**
     * 获取单元格对象
     *
     * @param sheet 表对象
     * @param row   行，从0开始
     * @param col   列，从0开始
     * @return row行col列的单元格对象
     */
    private static Cell getCell(Sheet sheet, int row, int col) {
        Row r = getRow(sheet, row);
        return getCell(r, col);
    }

    /**
     * 获取单元格对象
     *
     * @param row 行，从0开始
     * @param col 列，从0开始
     * @return 指定行对象上第col行的单元格
     */
    private static Cell getCell(Row row, int col) {
        col = (col < 0) ? 0 : col;
        Cell c = row.getCell(col);
        return (c == null) ? row.createCell(col) : c;
    }

    /**
     * 设置Excel样式和值
     *
     * @param cell
     * @param value
     */
    private static void setCellValue(Cell cell, Object value, String pattern) {
        if (value == null) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue("");
        } else if (value instanceof Byte || value.getClass() == byte.class) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue((Byte) value);
        } else if (value instanceof Short || value.getClass() == short.class) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue((Short) value);
        } else if (value instanceof Integer || value.getClass() == int.class) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue((Integer) value);
        } else if (value instanceof Long || value.getClass() == long.class) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue((Long) value);
        } else if (value instanceof Float || value.getClass() == float.class) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue((Float) value);
        } else if (value instanceof Double || value.getClass() == double.class) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue((Double) value);
        } else if (value instanceof Date) {
            cell.setCellType(CellType.STRING);
            cell.setCellValue(DateFormatUtils.format((Date) value, pattern));
        } else if (value instanceof BigDecimal) {
            cell.setCellType(CellType.STRING);
            cell.setCellValue(new DecimalFormat(pattern).format(value));
        } else if (value instanceof LocalDateTime) {
            cell.setCellType(CellType.STRING);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            cell.setCellValue(((LocalDateTime) value).format(formatter));
        } else if (value instanceof OffsetDateTime) {
            cell.setCellType(CellType.STRING);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            cell.setCellValue(((OffsetDateTime) value).format(formatter));
        } else if (value instanceof IBaseEnum) {
            cell.setCellType(CellType.STRING);
            cell.setCellValue(((IBaseEnum) value).getName());
        } else {
            cell.setCellType(CellType.STRING);
            cell.setCellValue((String) value);
        }
    }

    private static Map<Integer, String> getFieldValueJson(String valueJson) {
        String json = null;
        if (StringUtil.isBlank(valueJson)) {
            return null;
        }
        return JSON.parseObject(valueJson, Map.class);
    }

    public static class DateFormatterHolder {
        public static SimpleDateFormat getSimple(String patern) {
            return new SimpleDateFormat(patern);
        }
    }

    private static class Entry {
        public final PropertyDescriptor property;
        public final String name;
        public final String pattern;
        public final Map<Integer, String> json;
        public final int order;

        public Entry(PropertyDescriptor property, String name, String pattern, String json, int order) {
            this.property = property;
            this.name = name;
            this.pattern = pattern;
            this.json = getFieldValueJson(json);
            this.order = order;
        }

    }

}